/**
 * ImgCodeServlet
 *
 * @author WS
 * @date 2020/03/11
 */
package com.study.servlet;

import javax.imageio.ImageIO;
import javax.servlet.ServletException;
import javax.servlet.annotation.WebServlet;
import javax.servlet.http.HttpServlet;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import java.awt.*;
import java.awt.image.BufferedImage;
import java.io.IOException;
import java.util.Random;

@WebServlet(name = "imgCode",urlPatterns="/img/imgCode")
public class ImgCodeServlet extends HttpServlet {
    @Override
    protected void service(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException {
        //1.设置响应的数据类型，以输出JPEG格式的文件
        response.setContentType("image/jpeg");
        //2.设置页面不缓存
        response.setHeader("Pragma","No-cache");
        response.setHeader("Cache-Control","no-cache");
        response.setDateHeader("Expires", 0);
        //3.设置图象的大小
        int width = 60;
        int height = 30;
        //4.设置验证码的长度
        int length = 4;
        //5.在内存中创建图象BufferedImage对象
        BufferedImage image = new BufferedImage(width, height, BufferedImage.TYPE_INT_RGB);
        //6.取得指定尺寸的图像，所需的验证码随机获取。
        String checkCode = getImage(image,width,
                height,  length);
        //7.将验证码存入SESSION 名为"ValidateCode"，可以在Session中读取。
        request.getSession().setAttribute("ValidateCode",checkCode);
        //8.将BufferedImage对象转换为JPEG格式。通过response对象输出图像。
        try{
            ImageIO.write(image, "JPEG", response.getOutputStream());
        }catch(IOException e ){
            e.printStackTrace();
        }
        //9.清除输出响应缓冲区。
        response.flushBuffer();
    }
    /**
     * 随机取一个颜色Color对象
     */
    Color getRandColor(int fc, int bc)
    {
        Random random = new Random();
        if(fc>255)
            fc=255;
        if(bc>255)
            bc=255;
        int r=fc+random.nextInt(bc-fc);
        int g=fc+random.nextInt(bc-fc);
        int b=fc+random.nextInt(bc-fc);
        return new Color(r,g,b);
    }

    /**
     * 创建BufferedImage对象,并返回图片中的数据（字符串）
     * @param  	image 对象
     * @param	width 图像宽度
     * @param	height 图像高度
     * @param	length 字符串长度
     */
    private String getImage(BufferedImage image,int width,
                            int height, int length){
        // 可用的随机编码字码，可以用字符串表示，相应地用charAt(int index)方法取得某一字符。
        char[] code = { '0', '1', '2', '3', '4', '5', '6', '7', '8', '9' ,
                'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o',
                'p','q','r','s','t','u','v','w','x','y','z',
                'A','B','C','D','E','F','G','H','I','J','K','L','M','N','O',
                'P','Q','R','S','T','U','V','W','X','Y','Z'};
        // 可用的字体
        String []Fonts={"Times New Roman",
                "Verdana",
                "Arial Narrow",
                "Candara",
                "Californian FB",
                "Brush Script MT"
        };

        // 获取图形上下文
        Graphics g = image.getGraphics();
        // 生成随机类对象
        Random random = new Random();
        // 画边框
        g.fillRect(0, 0, width, height);
        // 选择颜色, 设定背景色
        g.setColor(getRandColor(160,200));
        // 随机产生155条干扰线，使图象中的认证码不易被其它程序探测到
        for (int i=0;i<155;i++)
        {
            int x = random.nextInt(width);
            int y = random.nextInt(height);
            int xl = random.nextInt(12);
            int yl = random.nextInt(12);
            //画随机线条
            g.drawLine(x,y,x+xl,y+yl);
        }
        // 保存随机产生的验证码字符。
        String sRand="";
        int t;
        // 取随机产生的验证码(字符长度由length指定)
        for (int i = 0;i < length; i++){
            t = random.nextInt(code.length);
            //随机选择一个字符
            String rand =  "" + code[t];
            sRand += rand;
            //随机选择颜色
            g.setColor(new Color(20+random.nextInt(110),20+random.nextInt(110),20+random.nextInt(110)));
            //随机选择字体，字体大小为（25+random.nextInt(5)）
            g.setFont(new Font(Fonts[random.nextInt(5)],Font.PLAIN,25+random.nextInt(5)));
            //在(13*i,15+random.nextInt(10))位置写一个字符，将验证码显示到图象中
            g.drawString(rand,13*i+6,15+random.nextInt(10));
        }
        // 释放图形上下文
        g.dispose();
        // 返回验证码
        return sRand;
    }
}
